import { _decorator, Component, Node, Vec3, Quat, Color, Sprite, SpriteFrame, Label, tween, Tween, UIOpacity, Material, director, Scene, Asset, resources, SpriteAtlas, UITransform, Prefab, instantiate, NodePool, Mat4, Camera } from 'cc';
const { ccclass, property } = _decorator;

/**
 * Cocos Creator 3.x 通用工具类
 * 包含常用工具方法，方便游戏开发
 */
export class CocosUtils {
    // 单例模式
    private static _instance: CocosUtils;
    public static get instance(): CocosUtils {
        if (!this._instance) {
            this._instance = new CocosUtils();
        }
        return this._instance;
    }

    // 私有构造函数，防止外部实例化
    private constructor() {}

    // ==================== 节点操作相关 ====================

    /**
     * 查找子节点
     * @param node 父节点
     * @param path 节点路径
     * @returns 找到的节点或null
     */
    public findChild(node: Node, path: string): Node | null {
        if (!node || !path) return null;
        return node.getChildByPath(path);
    }

    /**
     * 安全地获取节点上的组件
     * @param node 目标节点
     * @param type 组件类型
     * @returns 组件实例或null
     */
    public getComponent<T extends Component>(node: Node, type: new () => T): T | null {
        if (!node) return null;
        return node.getComponent(type) as T;
    }

    /**
     * 递归查找节点及其子节点中的组件
     * @param node 起始节点
     * @param type 组件类型
     * @returns 组件实例或null
     */
    public findComponentInChildren<T extends Component>(node: Node, type: new () => T): T | null {
        if (!node) return null;
        
        // 先检查当前节点
        const comp = node.getComponent(type);
        if (comp) return comp;
        
        // 递归检查子节点
        for (let i = 0; i < node.children.length; i++) {
            const childComp = this.findComponentInChildren(node.children[i], type);
            if (childComp) return childComp;
        }
        
        return null;
    }

    // ==================== 精灵操作相关 ====================

    /**
     * 动态切换精灵图片
     * @param sprite 精灵组件
     * @param spriteFrame 新的精灵帧
     */
    public changeSpriteFrame(sprite: Sprite, spriteFrame: SpriteFrame): void {
        if (sprite && spriteFrame) {
            sprite.spriteFrame = spriteFrame;
        }
    }

    //节点动态修改精灵图片
   setSpriteFrame (node: Node, path:string) {
       resources.load(path, SpriteFrame, (err, spriteFrame) => {
           node.getComponent(Sprite).spriteFrame = spriteFrame;
       });
   }

   // 修改为plist中某个图片
   setSpriteAtlas(node:Node, atlasPath:string, spriteName: string){
       resources.load(atlasPath, SpriteAtlas, function (err, atlas) {
           const frame = atlas.getSpriteFrame(spriteName);
           node.getComponent(Sprite).spriteFrame = frame
       });
   }

    /**
     * 设置精灵颜色
     * @param sprite 精灵组件
     * @param color 颜色值 (十六进制或Color对象)
     */
    public setSpriteColor(sprite: Sprite, color: Color | string): void {
        if (!sprite) return;
        
        if (typeof color === 'string') {
            // 处理十六进制颜色字符串
            const hexColor = color.replace('#', '');
            const r = parseInt(hexColor.substring(0, 2), 16) / 255;
            const g = parseInt(hexColor.substring(2, 4), 16) / 255;
            const b = parseInt(hexColor.substring(4, 6), 16) / 255;
            const a = hexColor.length > 6 ? parseInt(hexColor.substring(6, 8), 16) / 255 : 1;
            
            sprite.color = new Color(r, g, b, a);
        } else {
            sprite.color = color;
        }
    }

    // ==================== 动画与缓动相关 ====================

    /**
     * 节点淡入效果
     * @param node 目标节点
     * @param duration 持续时间(秒)
     * @param callback 完成回调
     */
    public fadeIn(node: Node, duration: number = 0.5, callback?: Function): void {
        if (!node) return;
        
        const opacity = node.getComponent(UIOpacity) || node.addComponent(UIOpacity);
        opacity.opacity = 0;
        
        tween(opacity)
            .to(duration, { opacity: 255 })
            .call(() => {
                if (callback) callback();
            })
            .start();
    }

    /**
     * 节点淡出效果
     * @param node 目标节点
     * @param duration 持续时间(秒)
     * @param callback 完成回调
     */
    public fadeOut(node: Node, duration: number = 0.5, callback?: Function): void {
        if (!node) return;
        
        const opacity = node.getComponent(UIOpacity) || node.addComponent(UIOpacity);
        opacity.opacity = 255;
        
        tween(opacity)
            .to(duration, { opacity: 0 })
            .call(() => {
                if (callback) callback();
            })
            .start();
    }

    /**
     * 缩放动画
     * @param node 目标节点
     * @param fromScale 起始缩放
     * @param toScale 目标缩放
     * @param duration 持续时间(秒)
     * @param callback 完成回调
     */
    public scaleAnimation(node: Node, fromScale: Vec3, toScale: Vec3, duration: number = 0.3, callback?: Function): void {
        if (!node) return;
        
        node.setScale(fromScale);
        
        tween(node)
            .to(duration, { scale: toScale })
            .call(() => {
                if (callback) callback();
            })
            .start();
    }

    /**
     * 按钮点击动画效果
     * @param node 按钮节点
     */
    public buttonClickEffect(node: Node): void {
        if (!node) return;
        
        const originalScale = node.scale.clone();
        const targetScale = new Vec3(originalScale.x * 0.9, originalScale.y * 0.9, originalScale.z);
        
        tween(node)
            .to(0.1, { scale: targetScale })
            .to(0.1, { scale: originalScale })
            .start();
    }

    // ==================== 数学计算相关 ====================

    /**
     * 限制数值范围
     * @param value 输入值
     * @param min 最小值
     * @param max 最大值
     * @returns 限制后的值
     */
    public clamp(value: number, min: number, max: number): number {
        return Math.min(Math.max(value, min), max);
    }

    /**
     * 线性插值
     * @param a 起始值
     * @param b 目标值
     * @param t 插值系数 (0-1)
     * @returns 插值结果
     */
    public lerp(a: number, b: number, t: number): number {
        return a + (b - a) * this.clamp(t, 0, 1);
    }

    /**
     * 向量线性插值
     * @param a 起始向量
     * @param b 目标向量
     * @param t 插值系数 (0-1)
     * @returns 插值后的向量
     */
    public lerpVec3(a: Vec3, b: Vec3, t: number): Vec3 {
        const x = this.lerp(a.x, b.x, t);
        const y = this.lerp(a.y, b.y, t);
        const z = this.lerp(a.z, b.z, t);
        return new Vec3(x, y, z);
    }

    /**
     * 生成随机整数
     * @param min 最小值(包含)
     * @param max 最大值(包含)
     * @returns 随机整数
     */
    public randomInt(min: number, max: number): number {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    /**
     * 生成随机浮点数
     * @param min 最小值
     * @param max 最大值
     * @returns 随机浮点数
     */
    public randomFloat(min: number, max: number): number {
        return Math.random() * (max - min) + min;
    }

    // ==================== 时间相关 ====================

    /**
     * 格式化时间(秒)为 mm:ss 格式
     * @param seconds 总秒数
     * @returns 格式化后的时间字符串
     */
    // public formatTime(seconds: number): string {
    //     const mins = Math.floor(seconds / 60);
    //     const secs = Math.floor(seconds % 60);
    //     return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    // }

    /**
     * 延迟执行
     * @param delay 延迟时间(秒)
     * @param callback 回调函数
     * @param target 回调目标
     */
    public delayCall(delay: number, callback: Function, target?: any): void {
        const node = new Node('DelayCall');
        director.getScene()?.addChild(node);
        
        const comp = node.addComponent(Component);
        let elapsed = 0;
        
        comp.schedule(() => {
            elapsed += director.getDeltaTime();
            if (elapsed >= delay) {
                callback.call(target);
                node.destroy();
            }
        });
    }

    // ==================== 场景管理相关 ====================

    /**
     * 加载场景
     * @param sceneName 场景名称
     * @param onProgress 加载进度回调
     * @param onComplete 加载完成回调
     */
    public loadScene(sceneName: string, onProgress?: (completedCount: number, totalCount: number, item: Asset) => void, onComplete?: () => void): void {
        director.preloadScene(sceneName, (completedCount, totalCount, item) => {
            if (onProgress) onProgress(completedCount, totalCount, item);
        }, (error) => {
            if (error) {
                console.error(`加载场景失败: ${sceneName}`, error);
                return;
            }
            director.loadScene(sceneName, onComplete);
        });
    }

    // ==================== 本地存储相关 ====================

    /**
     * 保存数据到本地存储
     * @param key 键名
     * @param value 值
     */
    public saveLocal(key: string, value: any): void {
        try {
            const data = JSON.stringify(value);
            localStorage.setItem(key, data);
        } catch (error) {
            console.error('保存数据到本地存储失败:', error);
        }
    }

    /**
     * 从本地存储读取数据
     * @param key 键名
     * @param defaultValue 默认值
     * @returns 读取到的数据或默认值
     */
    public getLocal<T>(key: string, defaultValue: T): T {
        try {
            const data = localStorage.getItem(key);
            if (data) {
                return JSON.parse(data) as T;
            }
        } catch (error) {
            console.error('从本地存储读取数据失败:', error);
        }
        return defaultValue;
    }

    // ==================== 其他工具方法 ====================

    /**
     * 深度克隆对象
     * @param obj 要克隆的对象
     * @returns 克隆后的对象
     */
    public deepClone<T>(obj: T): T {
        if (obj === null || typeof obj !== 'object') {
            return obj;
        }
        
        if (obj instanceof Array) {
            return obj.map(item => this.deepClone(item)) as unknown as T;
        }
        
        if (obj instanceof Object) {
            const cloned = {} as T;
            for (const key in obj) {
                if (obj.hasOwnProperty(key)) {
                    cloned[key] = this.deepClone(obj[key]);
                }
            }
            return cloned;
        }
        
        return obj;
    }

    /**
     * 生成唯一ID
     * @returns 唯一ID字符串
     */
    public generateId(): string {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    

    /**
     * 初始化对象池
     * @param prefab 
     * @param pool 
     * @param initCount 
     */
    initPool(prefab: Prefab, pool: NodePool, initCount: number) {
        for (let i = 0; i < initCount; ++i) {
            pool.put(instantiate(prefab));
        }
    }

     /*
    * 求圆周上等分点的坐标
    * ox,oy为圆心坐标
    * r为半径
    * count为等分个数
    */
    public getPoint(r: number, ox: number, oy: number, count: number){
        var point = []; //结果
        var radians = (Math.PI / 180) * Math.round(360 / count);//弧度
        for(var i = 0; i < count; i++){
            var x = ox + r * Math.sin(radians * i)
            var y = oy + r * Math.cos(radians * i)
            point.unshift({x:x,y:y}); //为保持数据顺时针
        }
        return point;
    }

    // 两点之间的距离
    public distance(p1: any, p2: any) { 
        var dx = Math.abs(p2.x - p1.x);
        var dy = Math.abs(p2.y - p1.y);
        return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
    }

    /**
     * 将 node 的锚点坐标转换到 targetNode 的本地空间
     */
    convertOtherNodeSpaceAR(node: Node, targetNode: Node): Vec3 | null {
        if (!node || !targetNode) {
            return null;
        }
        const nodeTrans = node.getComponent(UITransform);
        const targetTrans = targetNode.getComponent(UITransform);
        if (!nodeTrans || !targetTrans) {
            return null;
        }
        const worldPoint = nodeTrans.convertToWorldSpaceAR(Vec3.ZERO);
        return targetTrans.convertToNodeSpaceAR(worldPoint);
    }




}

// 全局访问简写
export const Utils = CocosUtils.instance;